package com.kamistoat.meimeistore.gateway.handler;

import com.kamistoat.meimeistore.commoncore.domain.R;
import com.kamistoat.meimeistore.commoncore.utils.ServletUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 网关模块统一异常处理。优先级低于 Sentinel异常处理，处理的异常也更加详细
 * ErrorWebExceptionHandler本身就继承自最底层的 WebExceptionHandler。
 * 且有一个默认的实现类为 DefaultErrorWebExceptionHandler，默认会根据异常类型在 /resources下寻找对应的前端页面进行返回。
 * 这里的实现类没有那么多作用，就是一个根据异常信息修改全局 ServerWebExchange中response
 */
@Configuration
@Order(-1)
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GatewayExceptionHandler.class);

    /**
     * @param serverWebExchange 全局ServerWebExchange
     * @param throwable         异常
     * @return Mono<Void>显示异常是否在该 handler完成处理
     */
    @Override
    public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
        // 同样若已提交，则不处理该异常
        if (serverWebExchange.getResponse().isCommitted()) {
            return Mono.error(throwable);
        }

        String msg;
        HttpStatus httpStatus;

        if (throwable instanceof NotFoundException) {
            // 服务未找到
            msg = "服务未找到";
            httpStatus = HttpStatus.NOT_FOUND;
        } else if (throwable instanceof ResponseStatusException) {
            // 找到服务，但路由异常
            ResponseStatusException responseStatusException = (ResponseStatusException) throwable;
            msg = responseStatusException.getMessage();
            httpStatus = HttpStatus.BAD_GATEWAY;
        } else {
            // 正常路由，但是内部业务异常
            msg = "内部业务服务异常:" + throwable.getMessage();
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
        }

        LOGGER.error("[网关异常处理]请求路径:{},异常信息:{}", serverWebExchange.getRequest().getPath(), throwable.getMessage());

        return ServletUtils.webFluxResponseWriter(serverWebExchange.getResponse(), httpStatus, msg, R.FAIL);
    }
}
